package com.xiaobias.a01;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.io.Resource;

import java.lang.reflect.Field;
import java.util.Locale;
import java.util.Map;

/**
 * BeanFactory 与 ApplicationContext 的区别.
 */
@SpringBootApplication
public class A01Application {

    private static final Logger log = LoggerFactory.getLogger(A01Application.class);

    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext context = SpringApplication.run(A01Application.class, args);
        // 一、BeanFactory与ApplicationContext的区别与联系
        /*
        1. 到底什么是 BeanFactory
            - 他是 ApplicationContext 的父接口
            - 他才是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能
            - BeanFactory实际上是ApplicationContext的成员变量
         */
        System.out.println(context);

        // 2. BeanFactory 能干点啥
        //  - 表面上只有 getBean
        //  - 实际上控制反转、基本的依赖注入、直至 Bean 的生命周期的各种功能， 都由它的实现雷提供
        Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
        singletonObjects.setAccessible(true);
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
        map.entrySet().stream().filter(e -> e.getKey().startsWith("component"))
                .forEach(e -> {
                    System.out.println(e.getKey() + "=" + e.getValue());
                });

        // 3.ApplicationContext比BeanFactory多点啥
        // 多啥？多实现了四个接口，分别是：
        // MessageSource: 支持信息的国际化和包含参数的信息的替换
        System.out.println(context.getMessage("hi", null, Locale.CHINA));
        System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
        System.out.println(context.getMessage("hi", null, Locale.JAPAN));
        System.out.println(context.getMessage("hi", null, Locale.getDefault()));
        // ResourcePatternResolver: 用于解析资源文件的策略接口
        Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");
        for (Resource resource : resources) {
            System.out.println(resource);
        }
        // EnvironmentCapable: 环境信息，系统环境变量，*.properties、*.application.yml等配置文件中的值
        System.out.println(context.getEnvironment().getProperty("java_home"));
        System.out.println(context.getEnvironment().getProperty("server.port"));
        // ApplicationEventPublisher: 发布事件对象（用于代码解耦）
        //  ApplicationEventPublisher详解：
        //    1.定义一个注册事件类，继承ApplicationEvent类
        //    2.定义一个监听类，用于监听事件，监听类上加@Component注解，将该类交给Spring管理，然后定义一个处理事件的方法，参数类型为注册事件类的对象（类型需要保持一致），方法头上需要加上@EventListener注解
        context.publishEvent(new UserRegisteredEvent(context));
        context.getBean(Component1.class).register();
    }
}